﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

/**
 * @file the camera
 *
 * @author LeonXie
 */

namespace Catsland.Core {
    public class Camera {
        // the view matrix, which transforms coordinates from world to view
        // set by setOrthographic
        public Matrix m_view;
        // the projection matrix, which transforms coordinates from view to projection
        // set by setOrthographic
        public Matrix m_projection;
        // the target GameObject the camera looks at. it can be null
        public GameObject m_target;
        // the width and height of the view port. set by setOrthographic
        public Vector2 m_viewSize;
        // the position of the camera
        public Vector3 m_position;

        public float m_editorCameraMoveSpeed = 0.01f;

        /**
         * @brief set orthographic for the camera
         *
         * @param width the width of the view port
         * @param height the height of the view port
         * @near near the near clipping plane
         * @far far the far clipping plane
         */
        public void setOrthographic(
            float width,
            float height,
            float near,
            float far) {
            m_viewSize = new Vector2(width, height);
            m_projection = Matrix.CreateOrthographic(width, height, near, far);
        }

        public void EditorUpdate() {
            KeyboardState keyboardState = Keyboard.GetState();
            if (keyboardState.IsKeyDown(Keys.W)) {
                MoveBiasIn2D(Vector2.UnitY * m_editorCameraMoveSpeed);
            }
            if (keyboardState.IsKeyDown(Keys.S)) {
                MoveBiasIn2D(Vector2.UnitY * -m_editorCameraMoveSpeed);
            }
            if (keyboardState.IsKeyDown(Keys.A)) {
                MoveBiasIn2D(Vector2.UnitX * -m_editorCameraMoveSpeed);
            }
            if (keyboardState.IsKeyDown(Keys.D)) {
                MoveBiasIn2D(Vector2.UnitX * m_editorCameraMoveSpeed);
            }
        }

        /**
         * @brief automatically pose the camera, if target exists
         *
         * this function will be invoked by engine automatically
         */
        public void Update() {
            LookAt(m_target);

        }

        public void LookAt(GameObject target) {
            if (target != null) {
                // pose the camera in front of the target
                Vector3 playerPosition = new Vector3(target.Position.X,
                    target.Position.Y * Mgr<Scene>.Singleton._yCos
                        + target.Height * Mgr<Scene>.Singleton._ySin,
                    0.0f);
                m_position = playerPosition + new Vector3(0.0f, 0.0f, 2.0f);
                Mgr<Camera>.Singleton.m_view = Matrix.CreateLookAt(m_position, playerPosition, Vector3.UnitY);
            }
        }

        public void Reset() {
            m_position = Vector3.Zero + Vector3.UnitZ * 2.0f;
            Mgr<Camera>.Singleton.m_view = Matrix.CreateLookAt(m_position, Vector3.Zero, Vector3.UnitY);
        }

        public void MoveBiasIn2D(Vector2 bias) {
            m_position.X += bias.X;
            m_position.Y += bias.Y;
            Vector3 target_position = m_position + new Vector3(0.0f, 0.0f, -2.0f);
            Mgr<Camera>.Singleton.m_view = Matrix.CreateLookAt(m_position, target_position, Vector3.UnitY);
        }

    }
}
